#ifndef _STLSerializer_h_
#define _STLSerializer_h_

#include <crtdbg.h>
#include <list>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include "Serializer.h"

namespace persist
{
template <class T> inline
Serializer& operator<<(Serializer& serializer, T*& t)
{
    Persistent* p = 0;
    if (!serializer.isReading())
    {
        p=dynamic_cast<Persistent* >(t);
    }
    serializer.persist(p);
    if (serializer.isReading())
    {
        t=dynamic_cast<T*>(p);
    }
    return serializer;
}
template <class T> inline
Serializer& operator<<(Serializer& serializer, T& t)
{
	
	Persistent* p = 0;
	//if (!serializer.isReading())
	//{
		p=dynamic_cast<Persistent* >(&t);
	//}

		_ASSERTE(p);
	

	serializer.persist(p);
	
	if (serializer.isReading())
	{
		T* pt=dynamic_cast<T*>(p);
		_ASSERTE(pt);
		t=*pt;
	}
	
	return serializer;
}
/*
template <class T>
Serializer& operator << (Serializer& serializer, CComPtr<T>& t)
{
    T* p = t;
    serializer << p;
    t = p;
    return serializer;
}
*/
template <class T> inline 
Serializer& serializeContainer(Serializer& serializer, T& l)
{
	long size = l.size();
    serializer << size;
    if (serializer.isReading())
    {
        if (size > 0) 
        {
            l.resize(size);
        }
		else 
        {
            l = T();
        }
    }
    T::iterator iterator = l.begin();
    for (; iterator != l.end(); iterator++)
    {
        serializer << *iterator;
    }
    return serializer;
}
//===============================================================================================
template <class T, class A> inline 
Serializer& operator << (Serializer& serializer, std::list<T, A>& l)
{
    return serializeContainer(serializer, l);
}
//===============================================================================================
template <class T, class A> inline 
Serializer& operator << (Serializer& serializer, std::vector<T, A>& v)
{
    return serializeContainer(serializer, v);
}
//===============================================================================================
template <class T, class A> inline 
Serializer& operator << (Serializer& serializer, std::deque<T, A>& q)
{
    return serializeContainer(serializer, q);
}
//===============================================================================================
inline Serializer& operator << (Serializer& serializer, std::string& s)
{
    return serializeContainer(serializer, s);
}
//===============================================================================================
template <class T, class A> 
class QueueSerializer : public std::queue<T, A>
{
public:
    QueueSerializer(const std::queue<T, A>& q) : std::queue<T, A>(q) {}
    void serialize(Serializer& serializer) { serializer << c; }
};
//===============================================================================================
template <class T, class A, class P> 
class PriorityQueueSerializer : public std::priority_queue<T, A, P>
{
public:
    PriorityQueueSerializer(const std::priority_queue<T, A, P>& q) : std::priority_queue<T, A, P>(q) {}
    void serialize(Serializer& serializer) { serializer << c; }
};
//===============================================================================================
template <class T, class A> inline 
Serializer& operator << (Serializer& serializer, std::queue<T, A>& q)
{
    QueueSerializer<T, A> qs(q);
    qs.serialize(serializer);
    if (serializer.isReading())
    {
        q = qs;
    }
    return serializer;
}
//===============================================================================================
template <class T, class A, class P> inline 
Serializer& operator << (Serializer& serializer, std::priority_queue<T, A, P>& q)
{
    PriorityQueueSerializer<T, A, P> qs(q);
    qs.serialize(serializer);
    if (serializer.isReading())
    {
        q = qs;
    }
    return serializer;
}
//===============================================================================================
template <class T> inline 
Serializer& serializeMap(Serializer& serializer, T& m)
{
    unsigned long size = m.size();
    serializer << size;
    if (serializer.isReading())
    {
        unsigned long i = 0;
        for (; i < size; i++)
        {
            T::key_type   k;
            T::referent_type   t;
            serializer << k << t;
            m.insert(T::value_type(k, t));
        }
        return serializer;
    }
    T::iterator iterator = m.begin();
    for (; iterator != m.end(); iterator++)
    {
        serializer << const_cast<T::key_type& >(iterator->first) << iterator->second;
    }
    return serializer;
}
//===============================================================================================
template<class K, class T, class Pr, class A> inline 
Serializer& operator << (Serializer& serializer, std::map<K, T, Pr, A>& m)
{
    return serializeMap(serializer, m);
}
//===============================================================================================
template<class K, class T, class Pr, class A> inline 
Serializer& operator << (Serializer& serializer, std::multimap<K, T, Pr, A>& m)
{
    return serializeMap(serializer, m);
}
//===============================================================================================
template <class T> inline 
Serializer& serializeSet(Serializer& serializer, T& m)
{
    ulong size = m.size();
    serializer << size;
    if (serializer.isReading())
    {
        ulong i = 0;
        for (; i < size; i++)
        {
            T::key_type   v;
            serializer << v;
            m.insert(v);
        }
        return serializer;
    }
    T::iterator iterator = m.begin();
    for (; iterator != m.end(); iterator++)
    {
        serializer << *iterator;
    }
    return serializer;
}
//===============================================================================================
template<class T, class Pr, class A> inline 
Serializer& operator << (Serializer& serializer, std::set<T, Pr, A>& m)
{
    return serializeSet(serializer, m);
}
//===============================================================================================
template<class T, class Pr, class A> inline 
Serializer& operator << (Serializer& serializer, std::multiset<T, Pr, A>& m)
{
    return serializeSet(serializer, m);
}

} //namespace
#endif
